﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SerialCapture
{
    public enum activeSerialState{
        opened,
        runnning,
        closed,
    };
    public enum SerialPortBaudRates : int
    {
        BaudRate_75 = 75,
        BaudRate_110 = 110,
        BaudRate_150 = 150,
        BaudRate_300 = 300,
        BaudRate_600 = 600,
        BaudRate_1200 = 1200,
        BaudRate_2400 = 2400,
        BaudRate_4800 = 4800,
        BaudRate_9600 = 9600,
        BaudRate_14400 = 14400,
        BaudRate_19200 = 19200,
        BaudRate_28800 = 28800,
        BaudRate_38400 = 38400,
        BaudRate_56000 = 56000,
        BaudRate_57600 = 57600,
        BaudRate_115200 = 115200,
        BaudRate_128000 = 128000,
        BaudRate_230400 = 230400,
        BaudRate_256000 = 256000
    };

    public enum SerialPortDatabits : int
    {
        FiveBits = 5,
        SixBits = 6,
        SeventBits = 7,
        EightBits = 8
    };
        
    ///calss name Serial
    ///description: 
    ///         this is the serial class for the use of serial port of windows.
    ///         member:
    ///             String serialPorts[]:  all available ports of windows. string array
    ///             serialPort _activePort: current active port.
    ///             serialStatus status:   current status of the active port.
    ///             encoding   encoding:   current encoding for the data over the serial port.
    ///         method:
    ///             receive data:
    ///             clear rx buffer:
    ///             close port:
    ///             open port:
    ///             
    class Serial
    {
        public string[] strPorts ;
        public mySerialPort activeSerial;
        public Boolean KPICheck;
        //public string traceFileName;

        public Serial(Boolean kpiCheck){
            this.KPICheck = kpiCheck;
        }

        public void setActivePort(string portName, SerialPortBaudRates baudrate,SerialPortDatabits databits, System.IO.Ports.StopBits stopBits, System.IO.Ports.Parity parity, System.IO.Ports.Handshake flowControl,string traceFile){
            activeSerial = new mySerialPort(portName, baudrate, databits, stopBits, parity, flowControl);
            activeSerial.traceFileName = traceFile;
            activeSerial.KPICheck = this.KPICheck;
        }

        #region my methods

        public void refreshPorts() {
            this.strPorts = mySerialPort.GetPortNames();
        }

        public void setBaudrate(SerialPortBaudRates baudrate)
        {
            activeSerial.myBaudrate = baudrate;
        }

        public void setPortName(string portName) {
            activeSerial.myName = portName;
        }

        public void setDataBits(SerialPortDatabits databits) {
            activeSerial.myDataBits = databits;
        }

        public void setStopBits(System.IO.Ports.StopBits stopBits) {
            activeSerial.myStopBits = stopBits;
        }

        public void setParity(System.IO.Ports.Parity parity) {
            activeSerial.myParity = parity;        
        }

        public void setFlowControl(System.IO.Ports.Handshake flowControl) {
            activeSerial.myFlowControl = flowControl;
        }
 #endregion  
    }


    ///             String serialPort:     current active serial port. string.
    ///             int32 baudrate:        baudrate of the serial port.
    ///             Parity parity:         parity of the serial port.
    ///             int32 databits:        databits of the serial port.
    ///             StopBits stopbits:     stopbits of the serial port.
    class mySerialPort : System.IO.Ports.SerialPort {
        public string myName;
        public SerialPortBaudRates myBaudrate;
        public SerialPortDatabits myDataBits;
        public System.IO.Ports.StopBits myStopBits;
        public System.IO.Ports.Parity myParity;
        public System.IO.Ports.Handshake myFlowControl;
        public Boolean marker;
        public int markerCount;
        public volatile Boolean KPICheck;

        private Log myLog;
        private KPITraceAnalyzer myKPIAnalyzer;
        //public Boolean isOpen;
        public volatile Boolean isReceiving;
        public volatile string currentTime;
        //public volatile string startTime;
        public volatile string traceFileName;

        public mySerialPort(string portName, SerialPortBaudRates baudrate,SerialPortDatabits databits, System.IO.Ports.StopBits stopBits, System.IO.Ports.Parity parity, System.IO.Ports.Handshake flowControl) {
            this.myBaudrate = baudrate;
            this.myName = portName;
            this.myDataBits = databits;
            this.myStopBits = stopBits;
            this.myParity = parity;
            this.myFlowControl = flowControl;
            this.isReceiving = false;
            this.ReadTimeout = 6000;
            this.Encoding = Encoding.ASCII;
            marker = false;
            this.KPICheck = false;
            markerCount = 0;

            this.BaudRate = Convert.ToInt32(this.myBaudrate);
            this.PortName = this.myName;
            this.DataBits = Convert.ToInt16(this.DataBits);
            this.Parity = this.myParity;
            this.StopBits = this.StopBits;
            this.Handshake = this.myFlowControl;

            this.ReadBufferSize = 4096;
            
            this.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(mySerialPort_DataReceived);
            this.myLog = new Log();
            this.myKPIAnalyzer = new KPITraceAnalyzer();

            if (this.IsOpen == true) {
                this.Close();
            }
        }

        void mySerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //myLog.appendLogText("Data Received event triggered.");
            if (form_main.on1sTimer)
            {
                form_main.on1sTimer = false;
                //receive the data and write to a file.
                //then set the on1sTimer as false
                if (!this.readRXBufferToFile())
                {
                    //write down trace and display warning notification.
                }
            }
            else {
                //myLog.appendLogText("1s timer not triggered. not write the data into file");
            }
            //else do nothing.
        }

        public Boolean openSerialPort(){
            //Close();
            try
            {
                myLog.appendLogText("trying to open serial port: " + this.myName);
                this.Open();
            }
            catch (Exception err){
                //write down traces.
                myLog.appendLogText("open serial port failed: [" + err.Message + "]",logFileTypeEnum.normal,logTypeEnum.ERROR);
                return false;    
            }
            return true;
            
        }

        private Boolean readRXBufferToFile()
        {
            //myLog.appendLogText("now write RX buffer into file");
            if (!form_main.traceFileAccessFlag)
            {
                form_main.traceFileAccessFlag = true;
                try
                {
                    FileStream fs = new FileStream(traceFileName, FileMode.Append);
                    //StreamWriter sw = new StreamWriter(
                    DateTime now = DateTime.Now;

                    if (this.marker) {
                        this.markerCount += 1;
                        currentTime = now.ToString("[yy-MM-dd]_hh.mm.ss: ");
                        string strFinal = "[" + currentTime + "]: " + " -------------------Set Marker " + this.markerCount.ToString() + "-------------------\n";
                        byte[] data = new ASCIIEncoding().GetBytes(strFinal);
                        fs.Write(data, 0, data.Length);
                        this.marker = false;
                        //changeContent("Set Marker " + this.markerCount.ToString());
                    }

                    byte[] receiveData = new byte[this.BytesToRead];
                    this.Read(receiveData, 0, receiveData.Length);
                    string strRcv = null;
                    //myLog.appendLogText("data in RX buffer, length " + receiveData.Length);
                    for (int i = 0; i < receiveData.Length; i++)
                    {
                        strRcv += Convert.ToChar(receiveData[i]);
                    }

                    //String finalString = "[" + currentTime + "]: " + strRcv + "\r\n";
                    //char[] splitor = "\r\n";
                    string[] finalStrArray = strRcv.Split('\n');

                    foreach (string s in finalStrArray)
                    {
                        s.Replace("\r", "");
                        if (this.KPICheck) {
                            myKPIAnalyzer.analyzeTrace(s);
                            //myLog.appendLogText("KPI Check Enabled.");
                        }
                        currentTime = now.ToString("[yy-MM-dd]_hh.mm.ss.fff: ");
                        string strFinal = "[" + currentTime + "]: " + s + "\n";
                        byte[] data = new ASCIIEncoding().GetBytes(strFinal);
                        fs.Write(data, 0, data.Length);
                    }

                    fs.Flush();
                    fs.Close();
                }
                catch (Exception err)
                {
                    //MessageBox.Show(err.Message);
                    //write down the traces. 
                    myLog.appendLogText("##################################Exception Happened#######################################");
                    myLog.appendLogText(err.ToString());
                    myLog.appendLogText("##################################Exception End#######################################");
                    return false;
                }

                form_main.traceFileAccessFlag = false;
                return true;
            }else{
                //myLog.appendLogText("Trace file is under accessing. skip the write to file operation.");
                return true;
            }
        }

    }
}
